// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
#include "Symbole.h"
#include "Multype.h"
#include <string>
#include <stack>

class SymboleValue;

using namespace std;
////////////////////////////////////////////////////////////////////////////////
class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:
    virtual Multype*  getValeur() {return NULL;} // méthode pure (non implémentée) qui rend la classe abstraite
    virtual void afficher(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }
      // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre

    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
    virtual string getCode(int indent) {return "";}
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    Multype* getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence
    string getCode(int indent);

  private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    Multype* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation
    string getCode(int indent);

  private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud {
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
     // construit une opération binaire : operandeGauche operateur OperandeDroit
   ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    Multype* getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    string getCode(int indent);

  private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};


class NoeudInstTq : public Noeud {
// <instTq>	::= tantque ( <expBool> ) faire <seqInst> fintantque
private:
	Noeud* expBool;
	NoeudSeqInst* seqInst;
public:
	NoeudInstTq(Noeud* expBool, Noeud* seqInst);
	~NoeudInstTq() {}
	Multype* getValeur();
	void afficher(unsigned short indentation=0);
	string getCode(int indent);
};

class NoeudInstRepeter : public Noeud
{
// <instRepeter>::= repeter <seqInst> jusqua ( <expBool> )
	private:
	Noeud* expBool;
	NoeudSeqInst* seqInst;
	public:
	NoeudInstRepeter(Noeud* expBool, Noeud* seqInst);
	~NoeudInstRepeter() {}
	Multype* getValeur();
	void afficher(unsigned short indentation=0);
	string getCode(int indent);
};

class NoeudInstPour : public Noeud
{
// <instPour>	::= pour ( <affectation> ; <expBool> ; <affectation> ) faire <seqInst> finpour
private:
	Noeud* expBool;
	NoeudSeqInst* seqInst;
	Noeud* affectation;
	Noeud* affectationPour;
	public:
	NoeudInstPour(Noeud* expBool, Noeud* seqInst, Noeud* affectation, Noeud* affectationPour);
	~NoeudInstPour() {}
	Multype* getValeur();
	void afficher(unsigned short indentation=0);
	string getCode(int indent);
};

class NoeudInstLire : public Noeud
{
	private:
		Noeud* variable;
	public:
		NoeudInstLire(Noeud* var);
		~NoeudInstLire() {}
		Multype* getValeur();
		void afficher(unsigned short indentation=0);
		string getCode(int indent);

};

class NoeudInstEcrire : public Noeud
{
	private:
		Noeud* variable;
	public:
		NoeudInstEcrire(Noeud* var);
		~NoeudInstEcrire() {}
		Multype* getValeur();
		void afficher(unsigned short indentation=0);
		string getCode(int indent);

};

class NoeudInstSi : public Noeud
{
// <instSi>	::= si ( <expBool> ) alors <seqInst> { sinonsi ( <expBool> ) alors <seqInst> } [ sinon <seqInst> ] finsi
	private :
		Noeud* expBool;
		NoeudSeqInst* instGauche;
		Noeud* instDroit;
	public:
		NoeudInstSi(Noeud* exp, Noeud* inst1, Noeud*  inst2);
		~NoeudInstSi() {}
		Multype* getValeur();
		void afficher(unsigned short indentation=0);
		string getCode(int indent);


};


class NoeudInstAppelFonction : public Noeud
{
// <instSi>	::= si ( <expBool> ) alors <seqInst> { sinonsi ( <expBool> ) alors <seqInst> } [ sinon <seqInst> ] finsi
	private :
		NoeudSeqInst* fonction;
		//stack<SymboleValue*> pile;
		vector<Noeud*> pile;
		vector<SymboleValue*> param;
		string nom;
	public:
		NoeudInstAppelFonction(NoeudSeqInst* f, vector<Noeud*> p,  vector<SymboleValue*> & _param, string nom );
		Multype* getValeur();
		void afficher(unsigned short indentation=0);
		string getCode(int indent);


};



#endif /* ARBRE_H_ */
